using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Xml;
using System.Text.RegularExpressions;

namespace NGNntpPlugIn
{
	/// <summary>
	/// Summary description for NewsgroupSelection.
	/// </summary>
	public class NewsgroupSelection : System.Windows.Forms.Form
	{
		private XmlDocument m_opmlFile;
		private string m_server;
		private string m_newsgroups;
		private NntpServer m_tempServer;

		private System.Windows.Forms.Button btnPost;
		private System.Windows.Forms.GroupBox groupBox1;
		private System.Windows.Forms.Label lblMessage;
		private System.Windows.Forms.Button btnCancel;
		private System.Windows.Forms.GroupBox groupBox2;
		private System.Windows.Forms.CheckedListBox clbNewsgroups;
		private System.Windows.Forms.ListBox lbServers;
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.Button btnAdd;
		private System.Windows.Forms.TextBox tbNewsgroup;
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public NewsgroupSelection(XmlDocument opmlFile, string server, string newsgroups)
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			//
			// TODO: Add any constructor code after InitializeComponent call
			//
			m_opmlFile = opmlFile;
			m_servers = new NntpServerCollection();
			m_server = server;
			m_newsgroups = newsgroups;
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		private NntpServerCollection m_servers;

		public NntpServerCollection SelectedServers
		{
			get { return m_servers; }
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.btnPost = new System.Windows.Forms.Button();
			this.groupBox1 = new System.Windows.Forms.GroupBox();
			this.lbServers = new System.Windows.Forms.ListBox();
			this.lblMessage = new System.Windows.Forms.Label();
			this.btnCancel = new System.Windows.Forms.Button();
			this.groupBox2 = new System.Windows.Forms.GroupBox();
			this.clbNewsgroups = new System.Windows.Forms.CheckedListBox();
			this.tbNewsgroup = new System.Windows.Forms.TextBox();
			this.label1 = new System.Windows.Forms.Label();
			this.btnAdd = new System.Windows.Forms.Button();
			this.groupBox1.SuspendLayout();
			this.groupBox2.SuspendLayout();
			this.SuspendLayout();
			// 
			// btnPost
			// 
			this.btnPost.Location = new System.Drawing.Point(200, 416);
			this.btnPost.Name = "btnPost";
			this.btnPost.TabIndex = 4;
			this.btnPost.Text = "Post";
			this.btnPost.Click += new System.EventHandler(this.btnPost_Click);
			// 
			// groupBox1
			// 
			this.groupBox1.Controls.Add(this.lbServers);
			this.groupBox1.Location = new System.Drawing.Point(8, 8);
			this.groupBox1.Name = "groupBox1";
			this.groupBox1.Size = new System.Drawing.Size(344, 160);
			this.groupBox1.TabIndex = 0;
			this.groupBox1.TabStop = false;
			this.groupBox1.Text = "NNTP Servers from NewsGator Subscriptions";
			// 
			// lbServers
			// 
			this.lbServers.Location = new System.Drawing.Point(8, 16);
			this.lbServers.Name = "lbServers";
			this.lbServers.Size = new System.Drawing.Size(328, 134);
			this.lbServers.TabIndex = 0;
			this.lbServers.SelectedIndexChanged += new System.EventHandler(this.lbServers_SelectedIndexChanged);
			// 
			// lblMessage
			// 
			this.lblMessage.ForeColor = System.Drawing.Color.Red;
			this.lblMessage.Location = new System.Drawing.Point(8, 416);
			this.lblMessage.Name = "lblMessage";
			this.lblMessage.Size = new System.Drawing.Size(192, 23);
			this.lblMessage.TabIndex = 6;
			this.lblMessage.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// btnCancel
			// 
			this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
			this.btnCancel.Location = new System.Drawing.Point(280, 416);
			this.btnCancel.Name = "btnCancel";
			this.btnCancel.Size = new System.Drawing.Size(72, 23);
			this.btnCancel.TabIndex = 5;
			this.btnCancel.Text = "Cancel";
			// 
			// groupBox2
			// 
			this.groupBox2.Controls.Add(this.clbNewsgroups);
			this.groupBox2.Location = new System.Drawing.Point(8, 176);
			this.groupBox2.Name = "groupBox2";
			this.groupBox2.Size = new System.Drawing.Size(344, 168);
			this.groupBox2.TabIndex = 1;
			this.groupBox2.TabStop = false;
			this.groupBox2.Text = "Newsgroups:";
			// 
			// clbNewsgroups
			// 
			this.clbNewsgroups.CheckOnClick = true;
			this.clbNewsgroups.Location = new System.Drawing.Point(8, 16);
			this.clbNewsgroups.Name = "clbNewsgroups";
			this.clbNewsgroups.Size = new System.Drawing.Size(328, 139);
			this.clbNewsgroups.Sorted = true;
			this.clbNewsgroups.TabIndex = 0;
			// 
			// tbNewsgroup
			// 
			this.tbNewsgroup.Location = new System.Drawing.Point(16, 368);
			this.tbNewsgroup.Name = "tbNewsgroup";
			this.tbNewsgroup.Size = new System.Drawing.Size(288, 20);
			this.tbNewsgroup.TabIndex = 2;
			this.tbNewsgroup.Text = "";
			// 
			// label1
			// 
			this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.85F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.label1.Location = new System.Drawing.Point(16, 352);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(328, 23);
			this.label1.TabIndex = 2;
			this.label1.Text = "Add a Newsgroup to post to. This does not get stored in NewsGator.";
			// 
			// btnAdd
			// 
			this.btnAdd.Location = new System.Drawing.Point(312, 368);
			this.btnAdd.Name = "btnAdd";
			this.btnAdd.Size = new System.Drawing.Size(40, 23);
			this.btnAdd.TabIndex = 3;
			this.btnAdd.Text = "Add";
			this.btnAdd.Click += new System.EventHandler(this.btnAdd_Click);
			// 
			// NewsgroupSelection
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(360, 448);
			this.ControlBox = false;
			this.Controls.Add(this.btnAdd);
			this.Controls.Add(this.tbNewsgroup);
			this.Controls.Add(this.label1);
			this.Controls.Add(this.groupBox2);
			this.Controls.Add(this.btnCancel);
			this.Controls.Add(this.lblMessage);
			this.Controls.Add(this.groupBox1);
			this.Controls.Add(this.btnPost);
			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
			this.MaximizeBox = false;
			this.MinimizeBox = false;
			this.Name = "NewsgroupSelection";
			this.ShowInTaskbar = false;
			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
			this.Text = "Newsgroup Selection";
			this.Closing += new System.ComponentModel.CancelEventHandler(this.NewsgroupSelection_Closing);
			this.Load += new System.EventHandler(this.NewsgroupSelection_Load);
			this.groupBox1.ResumeLayout(false);
			this.groupBox2.ResumeLayout(false);
			this.ResumeLayout(false);

		}
		#endregion

		private void NewsgroupSelection_Load(object sender, System.EventArgs e)
		{
			// get all the outline nodes in the opml file
			XmlNodeList nodes = m_opmlFile.SelectNodes("opml/body/outline");
			Regex rxLink = new Regex(@"(?<type>nntp|news)://(?<server>.*)/(?<newsgroup>.*)", RegexOptions.Compiled);

			NntpServerCollection servers = new NntpServerCollection();

			foreach(XmlNode node in nodes)
			{
				if (node.Attributes["xmlUrl"] != null)
				{
					// go through each outline in the opml file
					if(node.Attributes["xmlUrl"].Value.ToLower().StartsWith("news://") || node.Attributes["xmlUrl"].Value.ToLower().StartsWith("nntp://"))
					{
						// create a new server
						NntpServer server = new NntpServer(node, false);

						int index = -1;

						// check to see if this server is already in the collection
						if(servers.Contains(server.Server))
						{
							// this server is in the collection
							index = servers.IndexOf(server.Server);
						}
						else
						{
							// the server is not in the collection
							index = servers.Add(server);
						}

						if(index >= 0)
						{
							// the server index was found
							Match match = rxLink.Match(node.Attributes["xmlUrl"].Value);
							if(match.Groups.Count > 0)
							{
								// add this newsgroup to the server's newsgroup collection
								((NntpServer) servers[index]).Newsgroups.Add(new NntpNewsgroup(match.Groups["newsgroup"].Value, false));
							}
						}
					}
				}
			}

			if(m_server != "" & m_newsgroups != "")
			{
				// a server or newsgroup(s) was passed in
				string[] arrNewsgroups = m_newsgroups.Split(',');
				
				int serverIndex = servers.IndexOf(m_server);

				if(serverIndex >= 0)
				{
					// the server was found, find each newsgroup and select it
					foreach(string ng in arrNewsgroups)
					{
						int ngIndex = ((NntpServer) servers[serverIndex]).Newsgroups.IndexOf(ng);

						if(ngIndex >= 0)
						{
							// the newsgroup was found, select it
							((NntpNewsgroup) ((NntpServer) servers[serverIndex]).Newsgroups[ngIndex]).IsSelected = true;
						}
						else
						{
							// the newsgroup was not found, add it
							NntpNewsgroup newsgroup = new NntpNewsgroup(ng, true);

							((NntpServer) servers[serverIndex]).Newsgroups.Add(newsgroup);
						}
					}
				}


			}

			// set the servers variable
			m_servers = servers;

			// bind the servers to the listbox
			lbServers.DataSource = m_servers;

			if(lbServers.Items.Count == 0)
			{
				// no subscriptions were found
				lbServers.Enabled = false;
				clbNewsgroups.Enabled = false;
				btnPost.Enabled	= false;

				lblMessage.Text = "No Subscriptions Found";
			}
			else if(m_server != "")
			{
				// there are servers and one was passed in, find it and select it
				int serverIndex = m_servers.IndexOf(m_server);

				if(serverIndex >= 0)
				{
					// the server was found
					NntpServer srv = (NntpServer) m_servers[serverIndex];

					lbServers.SelectedItem = srv;
				}
			}
		}

		private void NewsgroupSelection_Closing(object sender, CancelEventArgs e)
		{
			bool selectedNewsgroups = false;

			if(DialogResult != DialogResult.Cancel)
			{
				foreach(NntpServer server in m_servers)
				{
					// go through each server to see if it has newsgroups selected
					if(server.IsNewsgroupSelected())
					{
						selectedNewsgroups = true;
						break;
					}
				}

				if(selectedNewsgroups)
				{
					// at least one newsgroup was selected
					DialogResult = DialogResult.OK;
				}
				else
				{
					// no item was selected
					lblMessage.Text = "Please select a newsgroup.";
					e.Cancel = true;
				}
			}
		}

		private void btnPost_Click(object sender, System.EventArgs e)
		{
			SaveSelection();
			DialogResult = DialogResult.OK;
		}

		private void lbServers_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			// save the current check listboxes
			SaveSelection();

			if(lbServers.SelectedItem != null)
			{
				// set the temporary server to the currently selected server
				m_tempServer = (NntpServer) lbServers.SelectedItem;

				// clear the current newsgroups
				clbNewsgroups.Items.Clear();

				// load the newsgroup check listbox
				foreach(NntpNewsgroup ng in m_tempServer.Newsgroups)
				{
					// add this newsgroup
					clbNewsgroups.Items.Add(ng, ng.IsSelected);
				}
			}
		}

		private void SaveSelection()
		{
			// save the current check listboxes
			if(m_tempServer != null)
			{
				// clear the selected status
				m_tempServer.Newsgroups.ClearSelectedStatus();

				foreach(NntpNewsgroup ng in clbNewsgroups.CheckedItems)
				{
					// set the selected status
					ng.IsSelected = true;
				}
			}
		}

		private void btnAdd_Click(object sender, System.EventArgs e)
		{
			bool isValid = false;

			if(lbServers.SelectedItem != null)
			{
				// a server is selected
				NntpServer server = (NntpServer) lbServers.SelectedItem;
				Nntp client = new Nntp();

				try
				{
					// connect to the server
					if(server.Authenticate)
						client.Connect(server.Server, server.UserName, server.Password);
					else
						client.Connect(server.Server);

					// get a listing of newsgroups
					ArrayList newsgroups = client.GetNewsgroups();

					// disconnect from the server
					client.Disconnect();

					// go through each of the newsgroups to validate the newsgroup entry
					foreach(string ng in newsgroups)
					{
						if(ng.ToLower() == tbNewsgroup.Text.ToLower())
						{
							isValid = true;
							break;
						}
					}

					if(isValid)
					{
						// this was a valid newsgroup, add it
						NntpNewsgroup ng = new NntpNewsgroup(tbNewsgroup.Text, true);
						server.Newsgroups.Add(ng);

						// add this item to the checkbox list
						clbNewsgroups.Items.Add(ng, true);

						lblMessage.Text = "Newsgroup Added.";
						tbNewsgroup.Text = "";
					}
					else
					{
						// this was a invalid newsgroup
						lblMessage.Text = "Invalid Newsgroup";
					}

				}
				catch (NntpException nEx)
				{
					// an error occurred, determine what caused the error
					string errorNumber = nEx.Message.Substring(0, 3);

					if(errorNumber == "400")
					{
						// service is discontinued
						lblMessage.Text = "The News Server has been discontinued.";
					}
					else if(errorNumber == "500")
					{
						// command not recognized
						lblMessage.Text = "There has been an internal error.";
					}
					else if(errorNumber == "501")
					{
						// command syntax error
						lblMessage.Text = "There has been an internal error.";
					}
					else if(errorNumber == "502")
					{
						// access restriction or permission denied
						lblMessage.Text = "Invalid Credentials.";
					}
					else if(errorNumber == "503")
					{
						// program fault - command not performed
						lblMessage.Text = "There has been an internal error.";
					}
					else
					{
						// unknown error
						lblMessage.Text = "An unknown error occurred.";
					}
				}
				catch (Exception ex)
				{
					// unknown error
					lblMessage.Text = "An unknown error occurred.";
				}
			}
		}
	}
}
